#include <gtest/gtest.h>
#include <QJsonObject>
#include <QJsonArray>
#include "JsonRpcRequest.h"

class TestJsonRpcRequest : public ::testing::Test
{
protected:
    void SetUp() override
    {
        // Setup code if needed
    }
    
    void TearDown() override
    {
        // Cleanup code if needed
    }
};

TEST_F(TestJsonRpcRequest, DefaultConstructor)
{
    JsonRpcRequest request;
    EXPECT_EQ(request.jsonrpc(), QString("2.0"));
    EXPECT_FALSE(request.hasId());
    EXPECT_TRUE(request.id().isNull());
    EXPECT_TRUE(request.method().isEmpty());
    EXPECT_FALSE(request.hasParams());
}

TEST_F(TestJsonRpcRequest, ConstructorWithMethod)
{
    JsonRpcRequest request(QVariant(), "testMethod");
    EXPECT_EQ(request.jsonrpc(), QString("2.0"));
    EXPECT_FALSE(request.hasId());
    EXPECT_EQ(request.method(), QString("testMethod"));
    EXPECT_FALSE(request.hasParams());
}

TEST_F(TestJsonRpcRequest, ConstructorWithMethodAndId)
{
    // Test with string ID
    JsonRpcRequest request1("test-id", "testMethod");
    EXPECT_TRUE(request1.hasId());
    EXPECT_EQ(request1.id().toString(), QString("test-id"));
    EXPECT_EQ(request1.method(), QString("testMethod"));
    
    // Test with numeric ID
    JsonRpcRequest request2(123, "testMethod");
    EXPECT_TRUE(request2.hasId());
    EXPECT_EQ(request2.id().toInt(), 123);
    EXPECT_EQ(request2.method(), QString("testMethod"));
}

TEST_F(TestJsonRpcRequest, ConstructorWithMethodParamsAndId)
{
    QJsonObject paramsObject;
    paramsObject["key1"] = "value1";
    paramsObject["key2"] = 123;
    
    JsonRpcRequest request2(456, "testMethod", paramsObject);
    EXPECT_TRUE(request2.hasId());
    EXPECT_EQ(request2.id().toInt(), 456);
    EXPECT_EQ(request2.method(), QString("testMethod"));
    EXPECT_TRUE(request2.hasParams());
}

TEST_F(TestJsonRpcRequest, MethodManagement)
{
    JsonRpcRequest request;
    
    // Initially empty
    EXPECT_TRUE(request.method().isEmpty());
    
    // Set method
    request.setMethod("testMethod");
    EXPECT_EQ(request.method(), QString("testMethod"));
    
    // Change method
    request.setMethod("anotherMethod");
    EXPECT_EQ(request.method(), QString("anotherMethod"));
    
    // Clear method
    request.setMethod("");
    EXPECT_TRUE(request.method().isEmpty());
}

TEST_F(TestJsonRpcRequest, ParamsManagement)
{
    JsonRpcRequest request;
    
    // Initially no params
    EXPECT_FALSE(request.hasParams());
    
    // Test with params
    QJsonObject paramsObject;
    paramsObject["key1"] = "value1";
    paramsObject["key2"] = 123;
    
    request.setParams(paramsObject);
    EXPECT_TRUE(request.hasParams());
    EXPECT_EQ(request.params(), paramsObject);
    
    // Clear params
    request.setParams(QJsonObject());
    EXPECT_FALSE(request.hasParams());
}

TEST_F(TestJsonRpcRequest, HasParams)
{
    JsonRpcRequest request;
    
    // Initially no params
    EXPECT_FALSE(request.hasParams());
    
    // Test with params
    QJsonObject paramsObject;
    paramsObject["test"] = "value";
    request.setParams(paramsObject);
    EXPECT_TRUE(request.hasParams());
    
    // After clearing params
    request.setParams(QJsonObject());
    EXPECT_FALSE(request.hasParams());
}

TEST_F(TestJsonRpcRequest, ToJson)
{
    // Test without ID and params
    JsonRpcRequest request1(QVariant(), "testMethod");
    QJsonObject json1 = request1.toJson();
    EXPECT_TRUE(json1.contains("jsonrpc"));
    EXPECT_EQ(json1["jsonrpc"].toString(), QString("2.0"));
    EXPECT_TRUE(json1.contains("method"));
    EXPECT_EQ(json1["method"].toString(), QString("testMethod"));
    EXPECT_FALSE(json1.contains("id"));
    EXPECT_FALSE(json1.contains("params"));
    
    // Test with string ID
    JsonRpcRequest request2("test-id", "testMethod");
    QJsonObject json2 = request2.toJson();
    EXPECT_TRUE(json2.contains("id"));
    EXPECT_EQ(json2["id"].toString(), QString("test-id"));
    
    // Test with numeric ID
    JsonRpcRequest request3(123, "testMethod");
    QJsonObject json3 = request3.toJson();
    EXPECT_TRUE(json3.contains("id"));
    EXPECT_EQ(json3["id"].toInt(), 123);
    
    // Test with params
    QJsonObject paramsObject;
    paramsObject["key1"] = "value1";
    paramsObject["key2"] = 123;
    JsonRpcRequest request5(456, "testMethod");
    request5.setParams(paramsObject);
    QJsonObject json5 = request5.toJson();
    EXPECT_TRUE(json5.contains("params"));
    EXPECT_TRUE(json5["params"].isObject());
    EXPECT_EQ(json5["params"].toObject(), paramsObject);
}

TEST_F(TestJsonRpcRequest, FromJson)
{
    bool ok = false;
    
    // Valid JSON with string ID and params
    QJsonObject json1;
    json1["jsonrpc"] = "2.0";
    json1["method"] = "testMethod";
    json1["id"] = "test-id";
    
    QJsonObject paramsObject;
    paramsObject["key1"] = "value1";
    paramsObject["key2"] = 456;
    json1["params"] = paramsObject;

    JsonRpcRequest request1 = JsonRpcRequest::fromJson(json1, &ok);
    EXPECT_TRUE(ok);
    EXPECT_TRUE(request1.hasId());
    EXPECT_EQ(request1.id().toString(), QString("test-id"));
    EXPECT_EQ(request1.method(), QString("testMethod"));
    EXPECT_TRUE(request1.hasParams());
    
    // Valid JSON with numeric ID and params
    QJsonObject json2;
    json2["jsonrpc"] = "2.0";
    json2["method"] = "anotherMethod";
    json2["id"] = 123;
    
    QJsonObject paramsObject1;
    paramsObject1["key1"] = "value1";
    paramsObject1["key2"] = 456;
    json2["params"] = paramsObject1;
    
    JsonRpcRequest request2 = JsonRpcRequest::fromJson(json2, &ok);
    EXPECT_TRUE(ok);
    EXPECT_TRUE(request2.hasId());
    EXPECT_EQ(request2.id().toInt(), 123);
    EXPECT_EQ(request2.method(), QString("anotherMethod"));
    EXPECT_TRUE(request2.hasParams());
    
    // Valid JSON without ID and params
    QJsonObject json3;
    json3["jsonrpc"] = "2.0";
    json3["method"] = "simpleMethod";
    
    JsonRpcRequest request3 = JsonRpcRequest::fromJson(json3, &ok);
    EXPECT_TRUE(ok);
    EXPECT_FALSE(request3.hasId());
    EXPECT_EQ(request3.method(), QString("simpleMethod"));
    EXPECT_FALSE(request3.hasParams());
    
    // Invalid JSON - missing jsonrpc
    QJsonObject json4;
    json4["method"] = "testMethod";
    json4["id"] = "test-id";
    
    JsonRpcRequest request4 = JsonRpcRequest::fromJson(json4, &ok);
    EXPECT_FALSE(ok);
    
    // Invalid JSON - wrong jsonrpc version
    QJsonObject json5;
    json5["jsonrpc"] = "1.0";
    json5["method"] = "testMethod";
    json5["id"] = "test-id";
    
    JsonRpcRequest request5 = JsonRpcRequest::fromJson(json5, &ok);
    EXPECT_FALSE(ok);
    
    // Invalid JSON - missing method
    QJsonObject json6;
    json6["jsonrpc"] = "2.0";
    json6["id"] = "test-id";
    
    JsonRpcRequest request6 = JsonRpcRequest::fromJson(json6, &ok);
    EXPECT_FALSE(ok);
    
    // Invalid JSON - non-string method
    QJsonObject json7;
    json7["jsonrpc"] = "2.0";
    json7["method"] = 123;
    json7["id"] = "test-id";
    
    JsonRpcRequest request7 = JsonRpcRequest::fromJson(json7, &ok);
    EXPECT_FALSE(ok);
    
    // Invalid JSON - invalid params type
    QJsonObject json8;
    json8["jsonrpc"] = "2.0";
    json8["method"] = "testMethod";
    json8["id"] = "test-id";
    json8["params"] = QJsonArray();
    
    JsonRpcRequest request8 = JsonRpcRequest::fromJson(json8, &ok);
    EXPECT_FALSE(ok);
}

TEST_F(TestJsonRpcRequest, IsValid)
{
    // Valid request with string ID
    JsonRpcRequest request1("test-id", "testMethod");
    EXPECT_TRUE(request1.isValid());
    
    // Valid request with numeric ID
    JsonRpcRequest request2(123, "testMethod");
    EXPECT_TRUE(request2.isValid());
    
    // Valid request without ID
    JsonRpcRequest request3(QVariant(), "testMethod");
    EXPECT_TRUE(!request3.isValid());
    
    // Valid request with params
    QJsonObject paramsObject;
    paramsObject["key1"] = "value1";
    JsonRpcRequest request4("test-id", "testMethod", paramsObject);
    EXPECT_TRUE(request4.isValid());
}

TEST_F(TestJsonRpcRequest, IsValidInvalid)
{
    // Invalid - empty method
    JsonRpcRequest request1;
    EXPECT_FALSE(request1.isValid());
    
    // Invalid - missing method
    JsonRpcRequest request2("test-id");
    EXPECT_FALSE(request2.isValid());
}
